// 导入 threejs
import * as THREE from 'three'
// 导入轨道控制器
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
// 导入lil.gui
import { GUI } from 'three/examples/jsm/libs/lil-gui.module.min.js'
// 导入 hdr 加载器. 专门用来加载hdr图的
import { RGBELoader } from 'three/examples/jsm/loaders/RGBELoader.js'
// 导入 gltF加载器，用来加载 gltf 的3D模型的
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js'
// 导入 DRACO 解码器，是加载压缩的 gltf模型的
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader.js'

// 创建场景
const scene= new THREE.Scene()

// 创建相机
const camera = new THREE.PerspectiveCamera(
  45,  // 视角
  window.innerWidth / window.innerHeight,
  0.1,  // 近平面
  1000   // 远平面
)

// 创建渲染器
const renderer = new THREE.WebGLRenderer()
renderer.setSize(window.innerWidth, window.innerHeight)   // 整屏渲染，canvas为基础

// 将画布添加到页面标签里
document.body.appendChild(renderer.domElement)

// 添加世界坐标辅助器，x,y,z轴的辅助线
const axesHelper = new THREE.AxesHelper(5)   // 并设置线段的长度为5
// 添加到场景当中
scene.add(axesHelper)

// 设置相机位置
// camera.position.z = 5   // 设置在哪个轴， x, y, z 这里设置z轴
// camera.lookAt(0, 0, 0)    // 设置相机看向什么位置，看向原点位置

// 为了看到z轴的线，调整相机位置
camera.position.z = 5   
camera.position.x = 3
camera.position.y = 2
camera.lookAt(0, 0, 0)  

// 添加轨道控制器， 先在上面导入
const controls = new OrbitControls(camera, renderer.domElement)   // renderer.domElement这个表示监听的元素是 canvas 元素， 渲染的标签
// const controls = new OrbitControls(camera, document.body)   // 监听body
// 设置带阻尼的惯性，阻尼感
controls.enableDamping = true         // 开启
// 设置阻尼系数
// controls.dampingFactor = 0.01          // 越小阻尼感越大
controls.dampingFactor = 0.5
// controls.autoRotate = true         // 自转，自动绕着目标旋转， 开启这个必须要使用 controls方法

// 做一个渲染函数， 不断渲染
function animate() {
  controls.update()    // 渲染的时候也要每次更新控制器
  requestAnimationFrame(animate)       // 相当于定时器，不断调用，一直渲染
  // 旋转功能
  // cube.rotation.x += 0.01
  // cube.rotation.y += 0.01
  // 渲染
  renderer.render(scene, camera)
}
animate()

// 监听窗口变化
window.addEventListener("resize", () => {
  // 重置渲染器宽高比
  renderer.setSize(window.innerWidth, window.innerHeight)
  // 重置相机宽高比
  camera.aspect = window.innerWidth / window.innerHeight
  // 更新相机投影矩阵 ， 一定要加
  camera.updateProjectionMatrix()
})

// rgbeLoader  加载hdr贴图
// let rgbeLoader = new RGBELoader()
// rgbeLoader.load("/picture/u.hdr", (envMap) => {  // 有一个回调函数，返回的就是加载后的纹理了
//   // 设置球形贴图
//   envMap.mapping = THREE.EquirectangularReflectionMapping
//   // 直接设置环境贴图
//   scene.environment = envMap
// })

// 把环境贴图换成环境光源
//增加环境光源
// const ambientLight = new THREE.AmbientLight(0xffffff, 1);  // 白光
const ambientLight = new THREE.AmbientLight(0xff00ff, 1);   // 绿色
scene.add(ambientLight);
//增加点光源
const pointLight = new THREE.PointLight(0xffffff, 5);
pointLight.position.set(-500, 1000, 100);
scene.add(pointLight);

// 创建 fog 场景 （雾）
// scene.fog = new THREE.Fog(0x999999, 0.1, 30)        // 线性雾，灰色，上面的长方体从 30 的位置渐渐的变成雾
scene.fog = new THREE.FogExp2(0x999999, 0.1)                  // 指数雾  第二个参数是密度
// 设置场景背景色
scene.background = new THREE.Color(0x999999)


// 实例化加载器 gltf， gltf是一种3D模型，是以 .gltf（json文本格式） 或者 .glb（二进制格式）
const gltfLoader = new GLTFLoader()
// 加载模型， 第一个参数是模型路径，第二个参数是一个回调
gltfLoader.load('/picture/car.gltf', (gltf) => {             // 模型要有光源才能有色彩， 不同颜色的光源会改变模型的颜色
  // 加载完成回调
  scene.add(gltf.scene)  // 整个场景上加上模型的场景
})

// 实例化解析器， 加载压缩后gltf模型
const dracoLoader = new DRACOLoader()
// dracoLoader.setDecoderPath()             // 设置本地解码器路径， 从 three module包里拷出来
// gltfLoader.setDRACOLoader(dracoLoader)    // 设置将 draco解码器加入到gltf加载器里

// 创建GUI
const gui = new GUI()